/**
 * <copyright>
 * Copyrigth 2007 Aurelien Moreau
 *
 * This file is part of ProcessShop.
 *
 * ProcessShop is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * ProcessShop is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with ProcessShop; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * </copyright>
 *
 * $Id$
 */
package net.yienyien.process2bpel.bpmn2bpd;

import java.util.HashMap;

import net.yienyien.process.bpd.BPDModel;
import net.yienyien.process.bpd.BPDObject;
import net.yienyien.process.bpd.BpdFactory;
import net.yienyien.process.bpd.BpdPackage;
import net.yienyien.process.bpd.ControlFlowRelation;
import net.yienyien.process.bpd.Task;
import net.yienyien.process.bpd.transducer.BPDProvider;
import net.yienyien.process.bpd.transducer.ProviderException;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.stp.bpmn.Activity;
import org.eclipse.stp.bpmn.ActivityType;
import org.eclipse.stp.bpmn.BpmnDiagram;
import org.eclipse.stp.bpmn.BpmnPackage;
import org.eclipse.stp.bpmn.Pool;
import org.eclipse.stp.bpmn.SequenceEdge;
import org.eclipse.stp.bpmn.util.BpmnSwitch;

public class BPMN2BPD extends BpmnSwitch  implements BPDProvider {
	
	private static final BpdFactory fact=BpdFactory.eINSTANCE;
	
	public static void main(String[] args) {
		ResourceSet rs = new ResourceSetImpl();
		rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("bpmn", new XMIResourceFactoryImpl());
		
		BpmnPackage.eINSTANCE.eClass();
		BpdPackage.eINSTANCE.eClass();
		
		Resource r=rs.getResource(URI.createFileURI("../toto/model/truc.bpmn"), true);
		BpmnDiagram diag=(BpmnDiagram) r.getContents().get(0);
		try {
			BPDModel model=(new BPMN2BPD()).getBPDmodel((EObject) diag.getPools().get(0));
			System.out.println("nodes:"+model.getObjects().size());
			System.out.println("edges:"+model.getRelations().size());
		} catch(ProviderException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public BPDModel getBPDmodel(EObject object) throws ProviderException {
		if(!(object instanceof Pool)) {
			throw new ProviderException("Convert a Pool");
		}
		return convert((Pool) object); 
	}

	private BPDModel convert(Pool pool) {
		BPDModel model=fact.createBPDModel();
		model.setFrom(pool);
		
		
		HashMap<Activity, BPDObject> computed=new HashMap<Activity, BPDObject>();
		
		for(Object o: pool.getVertices()) {
			Activity a=(Activity) o;
			compute(model, null, a, computed);
		}
		
		return model;
	}

	private BPDObject compute(BPDModel model, BPDObject from, Activity a, HashMap<Activity, BPDObject> computed) {
		BPDObject bpdObject=computed.get(a);
		if(bpdObject==null) {
			switch(a.getActivityType().getValue()) {
			case ActivityType.TASK:
				bpdObject=fact.createTask();
				((Task)bpdObject).setName(a.getName());
				break;
			case ActivityType.EVENT_START_EMPTY:
				bpdObject=fact.createStartEvent();
				break;
			case ActivityType.EVENT_END_EMPTY:
				bpdObject=fact.createEndEvent();
				break;
			case ActivityType.EVENT_INTERMEDIATE_TIMER:
			case ActivityType.EVENT_INTERMEDIATE_MESSAGE:
				bpdObject=fact.createIntermediateEvent();
				break;
			case ActivityType.GATEWAY_EVENT_BASED_EXCLUSIVE:
				if(a.getIncomingEdges().size()==1 && a.getOutgoingEdges().size()>=1) {
					bpdObject=fact.createEventBasedXOR();
				} else if(a.getIncomingEdges().size()>=1 && a.getOutgoingEdges().size()==1) {
					bpdObject=fact.createXORMerge();
				} else {
					//TODO
				}
				break;
			case ActivityType.GATEWAY_DATA_BASED_EXCLUSIVE:
				if(a.getIncomingEdges().size()==1 && a.getOutgoingEdges().size()>=1) {
					bpdObject=fact.createDataBasedXOR();	
				} else if(a.getIncomingEdges().size()>=1 && a.getOutgoingEdges().size()==1) {
					bpdObject=fact.createXORMerge();
				} else {
					//TODO
				}
				break;
			case ActivityType.GATEWAY_PARALLEL:
				if(a.getIncomingEdges().size()==1 && a.getOutgoingEdges().size()>=1) {
					bpdObject=fact.createParallelFork();
				} else if(a.getIncomingEdges().size()>=1 && a.getOutgoingEdges().size()==1) {
					bpdObject=fact.createParallelJoin();
				} else {
					//TODO
				}
				break;
			default:
				assert(false): a.getActivityType();
			}
			
			assert(bpdObject!=null);
			
			bpdObject.setFrom(a);
			bpdObject.setModel(model);
			computed.put(a, bpdObject);
			model.getObjects().add(bpdObject);
			
			for(Object o:a.getOutgoingEdges()) {
				SequenceEdge se=(SequenceEdge) o;
				compute(model, bpdObject, (Activity) se.getTarget(), computed);
			}
			
			
		}
		
		if(from!=null) {
			ControlFlowRelation relation=fact.createControlFlowRelation();
			relation.setModel(model);
			relation.setInput(from);
			relation.setOutput(bpdObject);
			model.getRelations().add(relation);
		}
		
		return bpdObject;
	}
}
